package com.hyc.serviceCenter.loadbalance.impl;

import com.hyc.serviceCenter.loadbalance.LoadBalance;

import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author 冷环渊
 * @date 2025/6/11 21:22
 * @description ConsistencyHashBalance
 */
public class ConsistencyHashBalance implements LoadBalance {
    //虚拟节点的个数
    public static final int VIRTUAL_NODE_NUM = 3;
    //虚拟节点的表示 127.0.0.1&VIRTUAL_NODE1
    public static final String VIRTUAL_NODE_STR = "&VIRTUAL_NODE";

    //存放虚拟节点的hash值 以及对应的节点名称  根据哈希值排序
    private SortedMap<Integer, String> virtualNodeMap = new TreeMap<>();
    //真实节点
    private List<String> realNode = new CopyOnWriteArrayList<>();

    public void init(List<String> addressList) {
        for (String server : addressList) {
            addNode(server);
        }

    }

    @Override
    public String balance(List<String> addressList) {
        if (addressList == null || addressList.isEmpty()) {
            throw new IllegalArgumentException("服务列表地址是空的");
        }
        String requestPath = UUID.randomUUID().toString();
        return getServer(requestPath, addressList);
    }

    private String getServer(String requestPath, List<String> addressList) {
        if (virtualNodeMap.isEmpty()) {
            init(addressList);
        }
        int hash = getHash(requestPath);
        Integer key = null;
        SortedMap<Integer, String> nodeMap = virtualNodeMap.tailMap(hash);
        if (nodeMap.isEmpty()) {
            key = virtualNodeMap.lastKey();
        } else {
            key = virtualNodeMap.firstKey();
        }
        String virtualNodePath = virtualNodeMap.get(key);
//        System.out.println("这次请求使用的虚拟节点为" + virtualNodePath);
        return virtualNodePath.substring(0, virtualNodePath.indexOf("&"));
    }

    public void addNode(String node) {
        if (!realNode.contains(node)) {
            realNode.add(node);
//            System.out.println("真实节点 " + node + "被添加节点列表");
            for (int i = 0; i < VIRTUAL_NODE_NUM; i++) {
                String virtualNodeName = node + VIRTUAL_NODE_STR + i;
                int hash = getHash(virtualNodeName);
                virtualNodeMap.put(hash, virtualNodeName);
//                System.out.println("虚拟节点 " + virtualNodeName + "被添加节点列表");
            }
        }
    }

    public void delNode(String node) {
        if (realNode.contains(node)) {
            realNode.remove(node);
            System.out.println("真实节点 " + node + "下线");
            for (int i = 0; i < VIRTUAL_NODE_NUM; i++) {
                String virtualNodeName = node + VIRTUAL_NODE_STR + i;
                int hash = getHash(virtualNodeName);
                virtualNodeMap.remove(hash, node);
                System.out.println("虚拟节点 " + virtualNodeName + "下线");
            }
        }
    }

    /**
     * 基于fnv1_32
     *
     * @author 冷环渊
     */
    public int getHash(String str) {
        final int FNV_PRIME = 16777619;
//        fnv初始哈希值 截断为int
        int hash = (int) 2166136261L;
        for (int i = 0; i < str.length(); i++) {
            hash = (hash ^ str.charAt(i)) * FNV_PRIME;
            // 增强步骤：增加位移和异或操作
            hash = (hash ^ (hash >>> 16)) * 0x85ebca6b; // 混合高低位
            hash ^= (hash >>> 13);                       // 二次扩散
            if (hash < 0) {
                hash = Math.abs(hash);
            }
        }
        return hash;
    }
}
